﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using Krile.Data;
using Krilib.Control.Surface;
using System.Windows.Forms;
using Krilib.Data;

namespace Krile.Forms.MainForm.Controls.Surface
{
    /// <summary>
    /// Dirty rendering control is here.Warning!
    /// </summary>
    internal class SurfaceRenderer
    {
        CompositionManager compman;

        internal IEnumerable<IMouseControllable> GetMouseControllables()
        {
            lock (soplocker)
            {
                if (sopclusters.Count > 0)
                    foreach (var c in sopclusters)
                        yield return c;
                if (parent.SelectedStatus != null && parent.SelectedStatus.BaseStatus.commands != null)
                    foreach (var c in parent.SelectedStatus.BaseStatus.commands)
                        yield return c;
            }
            yield return selectedMouseControllable;
            yield return baseMouseControllable;
        }

        IMouseControllable baseMouseControllable;

        internal class BaseController : IMouseControllable
        {
            SurfaceCore parent;
            SurfaceRenderer render;
            internal BaseController(SurfaceCore parent, SurfaceRenderer render)
            {
                this.parent = parent;
                this.render = render;
            }

            string helpTip = null;
            public string HelptipText
            {
                get { return helpTip; }
            }

            public bool HitTest(Point position)
            {
                long cpi = 0;
                if ((cpi = curPointingIndex(position.Y)) >= 0 &&
                    parent.Statuses != null && parent.Statuses.Length > cpi)
                {
                    Status target = parent.Statuses[cpi].BaseStatus;
                    StringBuilder sb = new StringBuilder();
                    sb.Append(target.user.name);
                    sb.Append(" : ");
                    if (target.text.HeaderText != null)
                        sb.Append("[" + target.text.HeaderText + "]");
                    string targetText = target.text.Original;
                    while (targetText != String.Empty)
                    {
                        if (targetText.Length > Core.Config.Appearance.Renderer.TooltipNewlineCount)
                        {
                            sb.Append(targetText.Substring(0, Core.Config.Appearance.Renderer.TooltipNewlineCount));
                            targetText = targetText.Substring(Core.Config.Appearance.Renderer.TooltipNewlineCount);
                            sb.Append(Environment.NewLine);
                        }
                        else
                        {
                            sb.Append(targetText);
                            targetText = String.Empty;
                        }
                    }
                    if (target.text.FooterText != null)
                        sb.Append("[" + target.text.FooterText + "]");
                    helpTip = sb.ToString();
                }
                else
                {
                    helpTip = null;
                }
                return true;
            }

            public void OnMouseClick(object sender, ChainMouseEventArgs e)
            {
                if (helpTip == null)
                    return;
                long cpi = -1;
                if ((cpi = curPointingIndex(e.Y)) >= 0 &&
                    parent.Statuses != null && parent.Statuses.Length > cpi)
                    parent.SelectedIndex = cpi;
            }

            public long curPointingIndex(long yposition)
            {
                yposition += parent.VerticalPosition;
                int idx = (int)Math.Floor((double)yposition / render.NormalItemHeight);
                //通常アイテム高さで概算した範囲内に選択中インデックスが存在していたら別処理
                if (parent.SelectedIndex >= 0 && parent.SelectedIndex <= idx)
                {
                    //通常アイテムの頭位置までを計算
                    long syp = render.NormalItemHeight * parent.SelectedIndex;
                    if (yposition >= syp && yposition <= syp + render.SelectedItemHeight)
                    {
                        //選択中のステータス領域をポイントしている
                        return -1;
                    }
                    //それよりも下
                    yposition -= syp + render.SelectedItemHeight;
                    //(残りの描画領域 / アイテム一つあたりの高さ) + 選択アイテムの位置 + 1(選択アイテムのカウント分)
                    long ret = (int)Math.Floor((double)yposition / render.NormalItemHeight) + parent.SelectedIndex + 1;
                    return ret;
                }
                else
                {
                    //選択インデックスはもっと下、もしくは選択していない
                    //だから普通に割る
                    return idx;
                }
            }

            public void OnMouseDoubleClick(object sender, ChainMouseEventArgs e)
            {
                this.OnMouseClick(sender, e);
            }

            public void OnMouseDown(object sender, ChainMouseEventArgs e) { }

            public void OnMouseEnter(object sender, ChainMouseEventArgs e) { }

            public void OnMouseLeave(object sender, ChainMouseEventArgs e) { }
            
            public void OnMouseMove(object sender, ChainMouseEventArgs e) { }

            public void OnMouseOver(object sender, ChainMouseEventArgs e) { }

            public void OnMouseUp(object sender, ChainMouseEventArgs e) { }
        }

        IMouseControllable selectedMouseControllable;

        internal class SelectedBase : IMouseControllable
        {
            SurfaceCore parent;
            SurfaceRenderer render;
            internal SelectedBase(SurfaceCore parent, SurfaceRenderer render)
            {
                this.parent = parent;
                this.render = render;
            }

            public string HelptipText { get { return null; } }

            public bool HitTest(Point position)
            {
                if(parent.SelectedIndex == -1)
                    return false;
                long sp = parent.SelectedIndex * render.NormalItemHeight - parent.VerticalPosition;
                long ep = sp + render.SelectedItemHeight;
                return sp <= position.Y && position.Y <= ep;
            }

            ContextMenuStrip cms = null;
            public void OnMouseClick(object sender, ChainMouseEventArgs e)
            {
                if(e.Button == MouseButtons.Right)
                {
                    //show context menu
                    cms = parent.CreateContextMenu();
                    cms.Show(parent, e.Location);
                }
            }

            public void OnMouseDoubleClick(object sender, ChainMouseEventArgs e)
            {
                this.OnMouseClick(sender, e);
            }

            public void OnMouseDown(object sender, ChainMouseEventArgs e) { }

            public void OnMouseEnter(object sender, ChainMouseEventArgs e) { }

            public void OnMouseLeave(object sender, ChainMouseEventArgs e) { }
            
            public void OnMouseMove(object sender, ChainMouseEventArgs e) { }

            public void OnMouseOver(object sender, ChainMouseEventArgs e) { }

            public void OnMouseUp(object sender, ChainMouseEventArgs e) { }
        }

        private SurfaceCore parent;
        internal SurfaceRenderer(SurfaceCore parent)
        {
            compman = new CompositionManager();
            this.parent = parent;
            baseMouseControllable = new BaseController(parent, this);
            selectedMouseControllable = new SelectedBase(parent, this);
        }

        internal int NormalItemHeight
        {
            get
            {
                if (Core.Config != null)
                    return Core.Config.Appearance.Renderer.Detail.NormalListHeight;
                else
                    return 0;
            }
        }

        int _selItemHeight = 0;
        internal int SelectedItemHeight
        {
            get { return _selItemHeight; }
            private set { _selItemHeight = value; }
        }

        internal void UpdateComposite()
        {
            if (Core.Config != null)
            {
                if (parent.SelectedStatus == null)
                    return;
                compman.ChangeCompositeTarget(parent.SelectedStatus.BaseStatus.text.MessageObjects);
                compman.UpdateComposition(parent.Width - Core.Config.Appearance.Renderer.UserNameArea - 2 - (Core.Config.Appearance.Renderer.Detail.TextRenderingMargin * 2));
                if (parent.SelectedStatus.BaseStatus.replyData != null)
                    SelectedItemHeight = 
                        compman.CompositedHeight + 
                        Core.Config.Appearance.Renderer.Detail.NormalListHeight +
                        Core.Config.Advanced.SelectedListNameCommandHeight + 2;
                else
                    SelectedItemHeight = compman.CompositedHeight + Core.Config.Advanced.SelectedListNameCommandHeight + 2;
                if (SelectedItemHeight < Core.Config.Appearance.Renderer.Detail.SelectedListMinHeight - 2)
                    SelectedItemHeight = Core.Config.Appearance.Renderer.Detail.SelectedListMinHeight;
                SelectedItemHeight += Core.Config.Appearance.Renderer.Detail.TextRenderingMargin * 2;
            }
        }

        internal void Draw(Graphics g, int yoffset)
        {
            lock (parent.statusesLocker)
            {
                lock (soplocker)
                {
                    sopclusters.Clear();
                }
                int ctor = 0;
                int cpos = 0;
                if (parent.Statuses != null)
                {
                    while (ctor < parent.Statuses.Length)
                    {
                        int bp = cpos;
                        if (parent.SelectedIndex == ctor)
                            bp += SelectedItemHeight;
                        else
                            bp += NormalItemHeight;
                        if (cpos > yoffset || bp > yoffset)
                        {
                            if (parent.SelectedIndex == ctor)
                                DrawSelectedItem(parent.Statuses[ctor], g, cpos - yoffset);
                            else
                                DrawNormalItem(parent.Statuses[ctor], ctor, g, cpos - yoffset);
                        }
                        cpos = bp;
                        if (cpos >= yoffset + parent.Height)
                            break;
                        ctor++;
                    }
                }
                if (cpos < yoffset + parent.Height)
                {
                    //remain area rendering
                    Rectangle draw = new Rectangle(0, cpos - yoffset, parent.Width, 0);
                    if (draw.Y < 0)
                        draw.Y = 0;
                    draw.Height = parent.Height - draw.Top;
                    g.FillRectangle(SystemBrushes.Control, draw);

                }
            }
        }

        private void DrawNormalItem(XStatus s, int i, Graphics g, int h)
        {
            //描画領域の取得
            Rectangle target = new Rectangle(0, h, parent.Width, NormalItemHeight);

            //背景の描画
            using (Brush b = new SolidBrush(GetBackgroundColor(s,i)))
                g.FillRectangle(b, target);

            //名前描画領域の確定
            Rectangle nameArea = target;
            nameArea.Width = Core.Config.Appearance.Renderer.UserNameArea;
            using (Brush b = new SolidBrush(Color.FromArgb(180, s.BaseStatus.ParentService.ServiceColor)))
                g.FillRectangle(b, nameArea);

            //アイコン画像
            Rectangle iconDest = nameArea;
            iconDest.Width = iconDest.Height;
            nameArea.X += iconDest.Right;
            nameArea.Width -= iconDest.Right;
            iconDest.Inflate(-1, -1);
            //アイコン画像の描画
            if (Core.ImageManager.IsCacheExists(s.BaseStatus.user.iconUri))
            {
                using (var img = Core.ImageManager.GetImage(s.BaseStatus.user.iconUri, false))
                {
                    if (img == null)
                        g.FillRectangle(Brushes.Red, iconDest);
                    else
                        g.DrawImage(img, iconDest);
                }
            }
            else
            {
                Core.ImageManager.GetImageCallback(s.BaseStatus.user.iconUri, false, new Krilib.Bridges.GetImageCallbackDelegate(
                    (u, img) => { if (img != null) { img.Dispose(); } parent.Refresher.RefreshSurface(false, true); }));
                g.FillRectangle(Brushes.White, iconDest);
            }
            //ユーザー名描画
            if (Core.Config.Appearance.Renderer.UserNameCentering)
                TextRenderer.DrawText(g, s.BaseStatus.user.name, Core.Config.Appearance.Font.Value, nameArea, s.BaseStatus.ParentService.ForeColor,
                    TextFormatFlags.EndEllipsis | TextFormatFlags.HorizontalCenter | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter);
            else
                TextRenderer.DrawText(g, s.BaseStatus.user.name, Core.Config.Appearance.Font.Value, nameArea, s.BaseStatus.ParentService.ForeColor,
                    TextFormatFlags.EndEllipsis | TextFormatFlags.Left | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter);
            target.X += nameArea.Right;
            target.Width -= nameArea.Right;
            if (target.Width <= 0)
                return;
            //ヘッダテキスト描画
            if (!String.IsNullOrEmpty(s.BaseStatus.text.HeaderText))
            {
                int reqWidth = TextRenderer.MeasureText(g, s.BaseStatus.text.HeaderText, Core.Config.Appearance.Font.Value, new Size(),
                     TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter).Width;
                Rectangle htrect = target;
                htrect.Width = reqWidth;
                htrect.X += 2;
                htrect.Inflate(0, -2);
                using (var b = new SolidBrush(Core.Config.Appearance.Renderer.Colors.ListHeaderFooterBackgroundColor.Value))
                    g.FillRectangle(b, htrect);
                TextRenderer.DrawText(g, s.BaseStatus.text.HeaderText, Core.Config.Appearance.Font.Value, htrect,
                    Core.Config.Appearance.Renderer.Colors.ListHeaderFooterTextColor.Value,
                    TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter);
                target.X = htrect.Right + 2;
                target.Width = parent.Width - target.X;
                if (target.Width <= 0)
                    return;
            }
            //フッタテキスト描画
            if (!String.IsNullOrEmpty(s.BaseStatus.text.FooterText))
            {
                int reqWidth = TextRenderer.MeasureText(g, s.BaseStatus.text.FooterText, Core.Config.Appearance.Font.Value, new Size(),
                     TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter).Width;
                if (reqWidth > target.Width - 4)
                    reqWidth = target.Width - 4;
                target.Width -= reqWidth + 4;
                Rectangle ftrect = target;
                ftrect.Width = reqWidth;
                ftrect.X = target.Right;
                ftrect.X--;
                ftrect.Inflate(0, -2);
                using (var b = new SolidBrush(Core.Config.Appearance.Renderer.Colors.ListHeaderFooterBackgroundColor.Value))
                    g.FillRectangle(b, ftrect);
                TextRenderer.DrawText(g, s.BaseStatus.text.FooterText, Core.Config.Appearance.Font.Value, ftrect,
                    Core.Config.Appearance.Renderer.Colors.ListHeaderFooterTextColor.Value,
                    TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter);
                if (target.Width <= 0)
                    return;
            }
            //本文描画
            TextRenderer.DrawText(g, s.BaseStatus.text.Original, Core.Config.Appearance.Font.Value, target, Color.Black,
                TextFormatFlags.EndEllipsis | TextFormatFlags.Left | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter);
        }

        private Color GetBackgroundColor(XStatus s, int i)
        {
            //自分への返信着色が有効になっている
            if ((s.Unread && Core.Config.Appearance.Renderer.Colors.ListReplyToMeNewestBackgroundColor.Enabled) ||
                Core.Config.Appearance.Renderer.Colors.ListReplyToMeBackgroundColor.Enabled)
            {
                //自分への返信かチェック
                if (s.BaseStatus.replyData != null)
                {
                    if ((s.BaseStatus.replyData.replyToUserId != null &&
                        s.BaseStatus.replyData.replyToUserId == s.BaseStatus.ParentAgent.GetMasterId()) ||
                        (s.BaseStatus.replyData.replyToId != null &&
                        s.BaseStatus.ParentAgent.Status.ServiceStatusIdExists(s.BaseStatus.replyData.replyToId) &&
                        Core.StatusManager.IdExists(s.BaseStatus.ParentAgent.Status.GetUidFromServiceStatusId(s.BaseStatus.replyData.replyToId)) &&
                        Core.StatusManager.GetStatus(s.BaseStatus.ParentAgent.Status.GetUidFromServiceStatusId(s.BaseStatus.replyData.replyToId)).user.id == s.BaseStatus.ParentAgent.GetMasterId()))
                    {
                        //返信だった
                        if (s.Unread)
                            return Core.Config.Appearance.Renderer.Colors.ListReplyToMeNewestBackgroundColor.Value;
                        else
                            return Core.Config.Appearance.Renderer.Colors.ListReplyToMeBackgroundColor.Value;
                    }
                }
            }

            if (parent.SelectedStatus != null)
            {
                if (Core.Config.Appearance.Renderer.Colors.ListReplyToSelectedBackgroundColor.Enabled &&
                    s.BaseStatus.replyData != null &&
                    s.BaseStatus.replyData.replyToId != null &&
                    s.BaseStatus.replyData.replyToId == parent.SelectedStatus.BaseStatus.id)
                    return Core.Config.Appearance.Renderer.Colors.ListReplyToSelectedBackgroundColor.Value;

                if (Core.Config.Appearance.Renderer.Colors.ListReplyFromSelectedBackgroundColor.Enabled &&
                    parent.SelectedStatus.BaseStatus.replyData != null &&
                    parent.SelectedStatus.BaseStatus.replyData.replyToId == s.BaseStatus.id)
                    return Core.Config.Appearance.Renderer.Colors.ListReplyFromSelectedBackgroundColor.Value;
            }

            if (Core.Config.Appearance.Renderer.Colors.ListMyPostBackgroundColor.Enabled &&
                s.BaseStatus.user.id == s.BaseStatus.ParentAgent.GetMasterId())
                return Core.Config.Appearance.Renderer.Colors.ListMyPostBackgroundColor.Value;

            if (s.Unread && Core.Config.Appearance.Renderer.Colors.ListNewestBackgroundColor.Enabled)
                return Core.Config.Appearance.Renderer.Colors.ListNewestBackgroundColor.Value;

            return i % 2 == 0 || !Core.Config.Appearance.Renderer.Colors.ListAlternateBackgroundColor.Enabled ?
            Core.Config.Appearance.BaseColorConfig.ListBackgroundColor.Value :
            Core.Config.Appearance.Renderer.Colors.ListAlternateBackgroundColor.Value;
        }

        private void DrawSelectedItem(XStatus s, Graphics g, int h)
        {
            if (s.Unread)
                s.Unread = false;
            //描画領域の初期化
            Rectangle target = new Rectangle(0, h, parent.Width - 1, SelectedItemHeight - 1);
            //枠の描画
            using (var p = new Pen(s.BaseStatus.ParentService.ServiceColor))
                g.DrawRectangle(p, target);
            target.Width++;
            target.Height++;
            target.Inflate(-1, -1);
            //背景描画
            using (var b = new SolidBrush(Core.Config.Appearance.BaseColorConfig.ListBackgroundColor.Value))
                g.FillRectangle(b, target);
            //ハイライトの描画
            Rectangle highlight = target;
            highlight.Width /= 4;
            if (highlight.Width < highlight.Height)
                highlight.Width = highlight.Height;
            highlight.X = target.Right - highlight.Width;
            using (Brush b = new LinearGradientBrush(highlight, GetBackgroundColor(s, 0), Color.Transparent, 225f))
                g.FillRectangle(b, highlight);

            Rectangle nameArea = target;
            nameArea.Width = Core.Config.Appearance.Renderer.UserNameArea - 1;
            //名前欄グラデーション描画
            using (var b = new LinearGradientBrush(nameArea, s.BaseStatus.ParentService.SecondaryColor, Core.Config.Appearance.BaseColorConfig.ListBackgroundColor.Value, 0f))
            {
                b.GammaCorrection = true;
                g.FillRectangle(b, nameArea);
            }
            //アイコン画像転送先確定
            Rectangle imageDest = nameArea;
            if (imageDest.Width < imageDest.Height)
            {
                imageDest.Height = imageDest.Width;
            }
            else
            {
                imageDest.Width = imageDest.Height;
                imageDest.X = (nameArea.Width - imageDest.Width) / 2;
            }
            imageDest.Inflate(-3, -3);
            //丸みのある矩形でクリップ
            var path = Imported.Snippets.Drawing.PathExtensions.GetCircularRectanglePathFromRectangle(imageDest, new Size(4, 4));
            var origClip = g.ClipBounds;
            g.SetClip(path);
            //ユーザーアイコン描画
            if (Core.ImageManager.IsCacheExists(s.BaseStatus.user.iconUri))
            {
                using (var img = Core.ImageManager.GetImage(s.BaseStatus.user.iconUri, false))
                {
                    if (img == null)
                        g.DrawImage(Properties.Resources.fail, imageDest);
                    else
                        g.DrawImage(img, imageDest);
                }
            }
            else
            {
                Core.ImageManager.GetImageCallback(s.BaseStatus.user.iconUri, false, new Krilib.Bridges.GetImageCallbackDelegate(
                    (u, img) => { if (img != null) { img.Dispose(); } parent.Refresher.RefreshSurface(false, true); }));
                g.DrawImage(Properties.Resources.loading, imageDest);
            }
            //クリップ解除
            g.SetClip(origClip);
            //サービスアイコン描画
            Rectangle iconDest = new Rectangle(imageDest.Right, imageDest.Bottom, 16, 16);
            iconDest.X -= 14;
            iconDest.Y -= 14;
            target.X += nameArea.Width;
            target.Width -= nameArea.Width;
            g.DrawImage(s.BaseStatus.ParentService.ServiceIcon, iconDest);
            lock (soplocker)
            {
                //アイコンクリック抽出
                var isop = new SingleOperation()
                {
                    Description = Lang.Renderer.ClickToExtractService,
                    HitArea = iconDest,
                    MouseEffect = true
                };
                isop.OnMouseClicked += new Action<ChainMouseEventArgs>((e) =>
                {
                    if (e.Button == MouseButtons.Left)
                        Data.DefaultKeyAssigns.AddTabFromService(s.BaseStatus, Keys.None);
                    else
                        e.SetThrowSub();
                });

                sopclusters.Add(isop);
                var usop = new SingleOperation()
                {
                    Description = Lang.Renderer.ClickToExtractUser,
                    HitArea = imageDest,
                    MouseEffect = true
                };
                usop.OnMouseClicked += new Action<ChainMouseEventArgs>((e) =>
                {
                    if (e.Button == MouseButtons.Left)
                        Data.DefaultKeyAssigns.AddTabFromUser(s.BaseStatus, Keys.None);
                    else
                        e.SetThrowSub();
                });
                sopclusters.Add(usop);

                //描画の実装
                Point loc = target.Location;
                if (Core.Config.Appearance.Renderer.NameAbove)
                    target.Y += Core.Config.Advanced.SelectedListNameCommandHeight;
                else
                    loc.Y = target.Bottom - Core.Config.Advanced.SelectedListNameCommandHeight;
                DrawNamebarElements(s, g, new Rectangle(loc, new Size(target.Width, Core.Config.Advanced.SelectedListNameCommandHeight)));
                target.Height -= Core.Config.Advanced.SelectedListNameCommandHeight;
                DrawBody(s, g, target);
            }
        }

        private void DrawNamebarElements(XStatus s, Graphics g, Rectangle bound)
        {
            //背景の描画
            using (var b = new SolidBrush(Color.FromArgb(120, s.BaseStatus.ParentService.SecondaryColor)))
                g.FillRectangle(b, bound);
            //マージンの確保
            bound.Inflate(-Core.Config.Appearance.Renderer.Detail.TextRenderingMargin, -Core.Config.Appearance.Renderer.Detail.TextRenderingMargin);
            //ユーザー名の描画準備
            string unm = s.BaseStatus.user.name + "(@" + s.BaseStatus.user.id + ")";
            int w = TextRenderer.MeasureText(g, unm, Core.Config.Appearance.Font.Value, new Size(),
                 TextFormatFlags.Left | TextFormatFlags.NoPrefix | TextFormatFlags.SingleLine).Width;
            if (s.BaseStatus.commands != null && s.BaseStatus.commands.Length > 0 && w > bound.Width - 10)
                w = bound.Width - 10;
            if (w < 0)
                w = 0;
            //オペレーション追加
            var sop = new SingleOperation()
            {
                Description = Lang.Renderer.ClickToShowUserpage,
                HitArea = new Rectangle(bound.Location, new Size(w, bound.Height)),
                MouseEffect = true
            };
            sop.OnMouseClicked += new Action<ChainMouseEventArgs>((e) =>
            {
                if (e.Button == MouseButtons.Left)
                    Subsystem.CommonOperation.CallBrowser(s.BaseStatus.user.profileUri);
                else
                    e.SetThrowSub();
            });
            sopclusters.Add(sop);
            //描画実行
            using (var f = new Font(Core.Config.Appearance.Font.Value, FontStyle.Underline))
                TextRenderer.DrawText(g, unm, f, bound, Core.Config.Appearance.BaseColorConfig.LinkTextColor.Value,
                     TextFormatFlags.Left | TextFormatFlags.NoPrefix | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis);
            //コマンド描画
            bound.X += w;
            bound.Width -= w;
            int rendered;
            var d = s.BaseStatus.commands.Draw(g, bound.Location, bound.Width, out rendered);
            if (d != null)
                sopclusters.Add(d);
            bound.Width -= rendered;
            if (bound.Width == 0) return;
            //投稿時刻描画準備
            TextRenderer.DrawText(
                g, s.BaseStatus.postedDate.ToString(Core.Config.Appearance.Renderer.Detail.DateTimeFormat),
                Core.Config.Appearance.Font.Value, bound, Core.Config.Appearance.BaseColorConfig.ForeSecondaryColor.Value,
                TextFormatFlags.Left | TextFormatFlags.NoPrefix | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis);
        }

        object soplocker = new object();
        List<IMouseControllable> sopclusters = new List<IMouseControllable>();
        //本体の描画
        private void DrawBody(XStatus s, Graphics g, Rectangle bound)
        {
            if (s.BaseStatus.replyData != null)
            {
                //返信部分の描画

                //描画領域の確定
                Rectangle rdArea = bound;
                rdArea.Height = Core.Config.Appearance.Renderer.Detail.NormalListHeight;
                bound.Y += rdArea.Height;
                bound.Height -= rdArea.Height;
                
                //角丸矩形で塗りつぶし
                var path = Imported.Snippets.Drawing.PathExtensions.GetCircularRectanglePathFromRectangle(rdArea, new Size(4, 4));
                using (var b = new SolidBrush(Core.Config.Appearance.Renderer.Colors.ListReplyBackgroundColor.Value))
                    g.FillPath(b, path);

                //当たり判定用に取っておく
                Rectangle orgrdArea = rdArea;
                //マージンの適用
                rdArea.Inflate(-Core.Config.Appearance.Renderer.Detail.TextRenderingMargin, -Core.Config.Appearance.Renderer.Detail.TextRenderingMargin);
                //テキストのフォーマット
                string showtext = s.BaseStatus.replyData.replyToUserName;
                if (showtext == null)
                    showtext = "@" + s.BaseStatus.replyData.replyToId;
                showtext = ">" + showtext;
                if (s.BaseStatus.replyData.replyToText != null)
                    showtext += ":" + s.BaseStatus.replyData.replyToText;
                else
                    showtext += ":" + "(no document)";
                //描画(該当返信先へジャンプできるかどうかで色を変更する)
                TextRenderer.DrawText(g, showtext, Core.Config.Appearance.Font.Value, rdArea,
                    s.BaseStatus.replyData.replyToId != null && s.BaseStatus.ParentAgent.Status.ServiceStatusIdExists(s.BaseStatus.replyData.replyToId) ?
                    Core.Config.Appearance.Renderer.Colors.ListReplyTextColor.Value :
                    Core.Config.Appearance.Renderer.Colors.ListReplyNotfoundTextColor.Value,
                TextFormatFlags.EndEllipsis | TextFormatFlags.Left | TextFormatFlags.NoPrefix | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter);


                var sop = new SingleOperation()
                {
                    Description = showtext,
                    HitArea = orgrdArea,
                    MouseEffect = true
                };

                sop.OnMouseClicked += new Action<ChainMouseEventArgs>((e) =>
                {
                    if (e.Button == MouseButtons.Left)
                    {

                        var uid = s.BaseStatus.replyData.ReplyOnClick();
                        if (uid > 0)
                        {
                            if (!parent.SelectStatusByUID(uid, true))
                                MessageBox.Show(Lang.Renderer.JumpToReplyError, "Jump to reply",
                                     MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        }
                    }
                    else
                    {
                        e.SetThrowSub();
                    }
                });
                sopclusters.Add(sop);
            }
            bound.Inflate(-Core.Config.Appearance.Renderer.Detail.TextRenderingMargin, -Core.Config.Appearance.Renderer.Detail.TextRenderingMargin);
            compman.Draw(g, bound.Location);
        }

        //なんかやるクラス
        class SingleOperation : IMouseControllable
        {
            internal string Description { get; set; }
            internal Rectangle HitArea { get; set; }
            internal bool MouseEffect { get; set; }

            public event Action<ChainMouseEventArgs> OnMouseClicked;
            public event Action<ChainMouseEventArgs> OnMouseEntered;
            public event Action<ChainMouseEventArgs> OnMouseLeaved;
            public string HelptipText
            {
                get { return Description; }
            }

            public bool HitTest(Point position)
            {
                return HitArea.HitTest(position);
            }

            public void OnMouseClick(object sender, ChainMouseEventArgs e)
            {
                if (OnMouseClicked != null)
                    OnMouseClicked.Invoke(e);
                else
                    e.SetThrowSub();
            }

            public void OnMouseDoubleClick(object sender, ChainMouseEventArgs e)
            {
                OnMouseClick(sender, e);
            }

            public void OnMouseDown(object sender, ChainMouseEventArgs e)
            {
                e.SetThrowSub();
            }

            public void OnMouseEnter(object sender, ChainMouseEventArgs e)
            {
                if (MouseEffect)
                    Core.FormManager.MainForm.SetCursor(Cursors.Hand);
                if (OnMouseEntered != null)
                    OnMouseEntered.Invoke(e);
                else if (!MouseEffect)
                    e.SetThrowSub();
            }

            public void OnMouseLeave(object sender, ChainMouseEventArgs e)
            {
                if (MouseEffect)
                    Core.FormManager.MainForm.SetCursor(Cursors.Default);
                if (OnMouseLeaved != null)
                    OnMouseLeaved.Invoke(e);
                else if(!MouseEffect)
                    e.SetThrowSub();
            }

            public void OnMouseMove(object sender, ChainMouseEventArgs e)
            {
                e.SetThrowSub();
            }

            public void OnMouseOver(object sender, ChainMouseEventArgs e)
            {
                e.SetThrowSub();
            }

            public void OnMouseUp(object sender, ChainMouseEventArgs e)
            {
                e.SetThrowSub();
            }
        }
    }
}
